﻿using System;
using System.Collections.Generic;
using System.Web.Mvc;
using System.Web.UI;

namespace MvcImproved.Generic
{
	public static class IControlModelHelper
	{
		public static IControlModelHelper<Model> Get<ParentModel, Model>(Func<ParentModel, Model> valueMember)
			where ParentModel : class
		{
			return new ControlModelHelper<ParentModel, Model>(valueMember);
		}
	}

	public interface IControlModelHelper<TModel>
	{
		TModel GetModel(ViewDataDictionary viewData);

		TModel GetModel(ViewUserControl<TModel> control);
	}

	class ControlModelHelper<TParentModel, TModel> : IControlModelHelper<TModel>
		where TParentModel : class
	{
		Func<TParentModel, TModel> _ValueMember;
		public ControlModelHelper(Func<TParentModel, TModel> valueMember)
		{
			_ValueMember = valueMember;
		}

		public TModel GetModel(ViewDataDictionary viewData)
		{
			TParentModel dataValue = (TParentModel)viewData.Model;
			return (dataValue != null) ? _ValueMember(dataValue) : default(TModel);
		}

		public TModel GetModel(ViewUserControl<TModel> control)
		{
			Control parentControl = control;
			ViewDataDictionary<TParentModel> parentViewData = null;
			while (parentControl != null)
			{
				var parentView = (parentControl as IViewDataContainer<TParentModel>);
				if (parentView != null)
				{
					parentViewData = parentView.ViewData;
					break;
				}
				var parentPage = (parentControl as System.Web.Mvc.ViewPage<TParentModel>);
				if (parentPage != null)
				{
					parentViewData = parentPage.ViewData;
					break;
				}
				var parentViewControl = (parentControl as System.Web.Mvc.ViewUserControl<TParentModel>);
				if (parentViewControl != null)
				{
					parentViewData = parentViewControl.ViewData;
					break;
				}
				parentControl = parentControl.Parent;
			}

			if (parentViewData != null)
			{
				TParentModel dataValue = parentViewData.Model;
				return (dataValue != null) ? _ValueMember(dataValue) : default(TModel);
			}
			else
				return GetModel(control.ViewData);
		}
	}
}
